import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { Request } from 'express'
import { jwtConstants } from "../constants";
import { RedisCacheService } from "src/redis/redis.service";

// 路由守卫
@Injectable()
export class AuthGuard implements CanActivate {

  constructor(
    private jwtService: JwtService,
    private readonly redisCacheService: RedisCacheService
  ) { }

  // 验证token
  async canActivate(context: ExecutionContext): Promise<boolean> {

    // 获取请求中的信息
    const request = context.switchToHttp().getRequest();
    const token = this.extractTokenFromHeader(request);

    if (!token) {
      throw new UnauthorizedException('token无效')
    }

    try {
      // 校验token
      const payload = await this.jwtService.verifyAsync(
        token,
        {
          secret: jwtConstants.secret // 秘钥
        }
      )

      // 判断redis中是否有该token
      const redisFlag = await this.redisCacheService.get(payload.loginName + '_token')
      if (!redisFlag) {
        throw new UnauthorizedException('token已过期')
      }

      // token 信息添加到请求体user字段上
      request['user'] = payload

    } catch (error) {
      throw new UnauthorizedException('token已过期')
    }

    return true
  }

  /**
   * 获取token
   * @param request 请求体
   * @returns token or undefined
   */
  extractTokenFromHeader(request: Request) {

    const cookies = request.headers.cookie?.replace(
      new RegExp(
        "(?:(?:^|.*;)\\s*" +
        encodeURIComponent('token').replace(/[-.+*]/g, "\\$&") +
        "\\s*\\=\\s*([^;]*).*$)|^.*$",
      ),
      "$1",
    );
    return cookies || undefined
  }
}